package com.heo.controller;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.log4j.Logger;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.util.StringUtil;
import com.heo.pojo.CommandResult;
import com.heo.pojo.ControlInfoEntity;
import com.heo.pojo.DeviceInfoEntity;
import com.heo.pojo.OrgInfoEntity;
import com.heo.pojo.req.QueryStatPara;
import com.heo.pub.DictEnum;
import com.heo.service.DeviceChannelService;
import com.heo.service.DeviceInfoService;
import com.heo.service.OrgInfoService;
import com.heo.util.RedisUtil;

/**
 * @author chichi
 */

@Controller
@Scope("singleton") // 1、为了性能。2、不需要多例。只要controller中不定义属性，那么单例完全是安全的。
@RequestMapping("/")
public class StatController extends BaseController
{
  private static Logger log = Logger.getLogger(StatController.class);

  @Resource(name = "orgInfoService")
  private OrgInfoService orgInfoService;

  @Resource(name = "deviceInfoService")
  private DeviceInfoService deviceInfoService;

  @Resource(name = "deviceChannelService")
  private DeviceChannelService deviceChannelService;

  /**
   * 统计设备信息
   * 
   * @param session
   * @param request
   * @param QueryStatPara
   * @return
   */
  @ResponseBody
  @RequestMapping(value = "/stat_device.do", method =
  { RequestMethod.POST })
  public JSONObject startDevice(HttpSession session, HttpServletRequest request, @RequestBody QueryStatPara queryStatPara)
  {
    try
    {
      log.debug("[统计设备状态]收到请求参数：" + queryStatPara.toString());

      // 校验参数
      HashMap<String, Object> paraMap = new HashMap<String, Object>();
      paraMap.put("appId", queryStatPara.getAppId());
      paraMap.put("appSecret", queryStatPara.getAppSecret());
      List<OrgInfoEntity> orgList = orgInfoService.listByMap(paraMap, "listByAppId");
      if (orgList == null || orgList.size() != 1)
      {
        CommandResult commandResult = new CommandResult(CommandResult.PublicResultCode.AUTHENTICATION_ERROR, CommandResult.PublicResultMsg.AUTHENTICATION_ERROR);
        return JSON.parseObject(commandResult.toString());
      }
      if (orgList == null || orgList.size() != 1)
      {
        CommandResult commandResult = new CommandResult(CommandResult.PublicResultCode.AUTHENTICATION_ERROR, CommandResult.PublicResultMsg.AUTHENTICATION_ERROR);
        return JSON.parseObject(commandResult.toString());
      }
      // 判断appid是否合法
      if (!(orgList.get(0).getAppId().equals(queryStatPara.getAppId()) && orgList.get(0).getAppSecret().equals(queryStatPara.getAppSecret())))
      {
        CommandResult commandResult = new CommandResult(CommandResult.PublicResultCode.AUTHENTICATION_ERROR, CommandResult.PublicResultMsg.AUTHENTICATION_ERROR);
        return JSON.parseObject(commandResult.toString());
      }

      int allDeviceNum = 0;// 设备总数
      int onlineDeviceNum = 0;// 在线设备数
      int offlineDeviceNum = 0;// 离线数量
      int busyDeviceNum = 0;// 工作中的通道数量
      int freeDeviceNum = 0;// 空闲数量
      int errorDeviceNum = 0;// 错误数量
      int lockedDeviceNum = 0;// 锁定中的数量

      // 查询当前appid下的设备，然后开始做统计
      Set<String> deviceStatusSet = new HashSet<String>();
      if (StringUtils.isEmpty(queryStatPara.getDeviceIMEI()))
      {
        // 请求方没有传设备参数过来，先去数据库找全部的设备
        paraMap = new HashMap<String, Object>();
        paraMap.put("appId", queryStatPara.getAppId());
        paraMap.put("appSecret", queryStatPara.getAppSecret());
        List<DeviceInfoEntity> deviceList = deviceInfoService.listByMap(paraMap, "selectAllByAppId");
        if (deviceList == null)
        {
          CommandResult commandResult = new CommandResult(CommandResult.PublicResultCode.SUCCESS, CommandResult.PublicResultMsg.SUCCESS);
          return JSON.parseObject(commandResult.toString());
        }
        for (int i = 0; i < deviceList.size(); i++)
        {
          deviceStatusSet.add(DictEnum.RedisKey.DEVICE_CONTROL + queryStatPara.getAppId() + ":" + deviceList.get(i).getDeviceImei());
        }
        allDeviceNum = deviceList.size();
      }
      else
      {
        // 根据请求方传过来的参数去查
        String[] deviceArrayPara = queryStatPara.getDeviceIMEI().split(",");
        for (int i = 0; i < deviceArrayPara.length; i++)
        {
          String tmpStr = deviceArrayPara[i];
          if (!StringUtils.isEmpty(tmpStr))
          {
            deviceStatusSet.add(DictEnum.RedisKey.DEVICE_CONTROL + queryStatPara.getAppId() + ":" + tmpStr.trim());
          }
        }
        allDeviceNum = deviceStatusSet.size();
      }
      log.debug("[统计设备状态]解析后需要查找以下设备的状态：" + deviceStatusSet);
      // 去redis里找到这些设备的状态集合(value集合)
      List<Object> statusList = RedisUtil.multiGet(new ArrayList<String>(deviceStatusSet));
      log.debug("[统计设备状态]查找结果：" + statusList);
      for (int i = 0; i < statusList.size(); i++)
      {
        Object redisObj = statusList.get(i);
        if (redisObj != null)
        {
          ControlInfoEntity controlInfo = (ControlInfoEntity) JSON.parseObject(redisObj.toString(), ControlInfoEntity.class);
          if (deviceStatusSet.contains(DictEnum.RedisKey.DEVICE_CONTROL + queryStatPara.getAppId() + ":" + controlInfo.getDeviceIMEI()) == true)
          {
            // 只计算在参数范围内的设备
            onlineDeviceNum++;
            Integer nums[] = controlInfo.getBusyDeviceNum();
            busyDeviceNum = nums[0] > 0 ? (busyDeviceNum + 1) : busyDeviceNum;
            freeDeviceNum = nums[1] > 0 ? (freeDeviceNum + 1) : freeDeviceNum;
            errorDeviceNum = nums[2] > 0 ? (errorDeviceNum + 1) : errorDeviceNum;
          }
        }
      }

      // 把lockSet里的数据进行去重
      HashSet<String> lockSet = new HashSet<String>();
      Set<String> allLockSet = RedisUtil.keys("\\[LOCK_STATUS\\]" + queryStatPara.getAppId() + "*");

      for (String str : allLockSet)
      {
        if (str != null)
        {
          str = str.split(":")[1];// 取出来imei号
          if (str != null && deviceStatusSet.contains(DictEnum.RedisKey.LOCK_STATUS + queryStatPara.getAppId() + ":" + str) == true)
          {
            lockSet.add(str);
          }
        }
      }
      lockedDeviceNum = lockSet.size();
      offlineDeviceNum = allDeviceNum - onlineDeviceNum;

      CommandResult commandResult = new CommandResult(CommandResult.PublicResultCode.SUCCESS, CommandResult.PublicResultMsg.SUCCESS);
      commandResult.setChannelInfoList(null);
      commandResult.setAllDeviceNum(allDeviceNum);
      commandResult.setBusyDeviceNum(busyDeviceNum);
      commandResult.setErrorDeviceNum(errorDeviceNum);
      commandResult.setFreeDeviceNum(freeDeviceNum);
      commandResult.setLockedDeviceNum(lockedDeviceNum);
      commandResult.setOnlineDeviceNum(onlineDeviceNum);
      commandResult.setOfflineDeviceNum(offlineDeviceNum);
      return JSON.parseObject(commandResult.toString());
    }
    catch (Exception e)
    {
      log.error(e.getMessage(), e);
      // 未知错误
      CommandResult pushResult = new CommandResult(CommandResult.PublicResultCode.UNKNOW_ERROR, CommandResult.PublicResultMsg.UNKNOW_ERROR);
      return JSON.parseObject(pushResult.toString());
    }
  }

}
